/*
 * @Author: 吴世扬 18368095041@163.com
 * @Date: 2024-07-10 09:21:42
 * @LastEditors: 吴世扬 18368095041@163.com
 * @LastEditTime: 2025-08-13 08:36:39
 * @FilePath: /grid-center-people-app/src/other/rollupPlugins/rollupPluginPnpmpath.ts
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */

import type { InputPluginOption, PluginContext } from 'rollup';
import { resolve as pathResolve, normalize, dirname, sep } from 'path';
import { lstatSync, readlink } from 'fs';
// import { type as osType } from 'os';

// const isWindows = osType() === 'Windows_NT';

// 从绝对路径获取node_modules的绝对路径或从绝对路径获取获取符号链接绝对路径的node_modules的绝对路径
const getNodeModulesByAbsolutePath = async (path: string) => {
    const stats = lstatSync(path);
    if (stats.isSymbolicLink()) {
        const relativePath = await new Promise<string>((resolve, reject) => {
            readlink(path, async (err, resolvedPath) => {
                if (err) return reject(err);
                resolve(resolvedPath);
            });
        });
        const baseDirPath = dirname(path);
        const absolutePath = pathResolve(baseDirPath, relativePath);
        const nodeModulesIndex = absolutePath.lastIndexOf('node_modules');
        if (nodeModulesIndex === -1)
            Promise.reject(
                new Error(
                    `[pnpmPathPlugin] ${path}对应的符号链接下没有node_modules`
                )
            );

        const parentNodeModulesPath = absolutePath.substring(
            0,
            nodeModulesIndex + 'node_modules'.length
        );
        return Promise.resolve({
            isSymbolicLink: true,
            nodeModules: parentNodeModulesPath
        });
    } else {
        const nodeModulesIndex = path.lastIndexOf('node_modules');
        if (nodeModulesIndex === -1)
            Promise.reject(
                new Error(`[pnpmPathPlugin] ${path}路径下没有node_modules`)
            );

        const parentNodeModulesPath = path.substring(
            0,
            nodeModulesIndex + 'node_modules'.length
        );
        return Promise.resolve({
            isSymbolicLink: false,
            nodeModules: parentNodeModulesPath
        });
    }
};

// 从最后的nodeModules后获取路径数组
const getLastNodeModulesPathList = (path: string) => {
    const arr = normalize(path).split(sep);
    let isPush = false;
    const paths: string[] = [];
    const lastIndex = arr.findLastIndex((item) => item === 'node_modules');
    arr.reduce((previous, current, currentIndex) => {
        let returnVal = previous;
        if (current) {
            returnVal = `${returnVal}${currentIndex !== 0 ? sep : ''}${current}`;
            if (isPush) {
                // paths.push(isWindows ? returnVal.substring(1) : returnVal);
                paths.push(returnVal);
            }
            if (current === 'node_modules' && currentIndex >= lastIndex) {
                isPush = true;
            }
        }
        return returnVal;
    }, '');
    return paths;
};

// 用esbuild的build.resolve处理路径
const resolvePath = async (
    paths: string[],
    args: { source: string; importer: string },
    resolve: PluginContext['resolve']
) => {
    try {
        const { source: importPath, importer } = args;
        for (let i = 0; i < paths.length; i++) {
            const path = paths[i];
            const { isSymbolicLink, nodeModules } =
                await getNodeModulesByAbsolutePath(path);
            if (isSymbolicLink) {
                const result = await resolve(importPath, nodeModules);
                if (result) {
                    return Promise.resolve(result);
                }
            }
        }
        throw new Error(
            `[rollupPluginPnpmpath]无法处理${importer}里的"${importPath}"`
        );
    } catch (e) {
        return Promise.reject(e);
    }
};

export const rollupPluginPnpmpath = (): InputPluginOption => {
    return {
        name: 'rollup-plugin-pnpmpath',
        resolveId: {
            async handler(source, importer) {
                if (
                    importer === undefined ||
                    !/^[@a-zA-Z][a-zA-Z].*$/.test(source) ||
                    importer.indexOf('node_modules') === -1
                ) {
                    return null; // null会调用其他resolveId处理，最终使用默认逻辑
                }
                // console.log(args);
                // 非node_modules的包引用的包直接默认esbuild导入逻辑处理
                const result = await this.resolve(source, importer);
                // 通用逻辑获取到路径，否则直接下一步处理符号链接导致无法找到路径的问题
                if (result) {
                    return Promise.resolve({
                        ...result
                    });
                }

                try {
                    const resolveDir = dirname(importer);
                    // node_modules的包引用的包需特殊处理，因为pnpm包依赖目录结构不是平铺的
                    const paths = getLastNodeModulesPathList(resolveDir);
                    const result = await resolvePath(
                        paths,
                        { source, importer },
                        this.resolve
                    );
                    // console.log(result);
                    return Promise.resolve({
                        ...result
                    });
                } catch (e) {
                    return Promise.reject(e);
                }
            }
        }
    };
};
